package com.dss.auto_deploy.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dss.auto_deploy.config.WebsocketEndPoint;
import com.dss.auto_deploy.constants.AutoConstants;
import com.dss.auto_deploy.domain.AdmDocker;
import com.dss.auto_deploy.domain.AdmMq;
import com.dss.auto_deploy.domain.Server;
import com.dss.auto_deploy.dto.AdmMqAddDto;
import com.dss.auto_deploy.dto.AdmMqPageDto;
import com.dss.auto_deploy.dto.AdmMqUpdateDto;
import com.dss.auto_deploy.dto.WsSendDto;
import com.dss.auto_deploy.mapper.AdmDockerMapper;
import com.dss.auto_deploy.mapper.AdmMqMapper;
import com.dss.auto_deploy.service.IAdmMqService;
import com.dss.auto_deploy.service.IServerService;
import com.dss.auto_deploy.util.*;
import com.dss.auto_deploy.vo.AdmMqVo;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.model.Container;
import com.jcraft.jsch.Session;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;


/**
* @Description:mq消息队列Service实现类
* @author dongshoushan
* @date 2022-11-03 19:24:15
*/
@Service
@Slf4j
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
public class AdmMqServiceImpl  extends ServiceImpl<AdmMqMapper,AdmMq> implements IAdmMqService {

    /**
    *
    * mq消息队列Mapper
    */
    private final AdmMqMapper admMqMapper;
    private final ThreadPoolTaskExecutor threadPoolTaskExecutor;
    private final RemoteSshUtil remoteSshUtil;
    private final AdmDockerMapper admDockerMapper;
    private final IServerService serverService;
    private final WebsocketEndPoint websocketEndPoint;
    private final DockerUtil dockerUtil;
    /**
    * 新增mq消息队列
    * @param admMqAddDto
    * @return Long
    */
    @Override
    public int insert(AdmMqAddDto admMqAddDto){
        AdmMq admMq = BeanUtils.copy(admMqAddDto, AdmMq.class);
        int insert = admMqMapper.insert(admMq);
        if (insert == 1) {
            log.info("新增成功{}",JacksonUtils.toString(admMq));
        }
        return insert;
    }


    /**
    * 修改mq消息队列
    * @param admMqUpdateDto
    * @return Long
    */
    @Override
    public int update(AdmMqUpdateDto admMqUpdateDto){
        AdmMq admMq = BeanUtils.copy(admMqUpdateDto, AdmMq.class);
        int number = admMqMapper.updateById(admMq);
        if (number == 1) {
            log.info("修改成功{}",JacksonUtils.toString(admMq));
        }
        return number;
    }


    /**
    * 批量删除mq消息队列
    * @param ids
    * @return Long
    */
    @Override
    public void deleteBatch(Long[] ids){
        this.removeByIds(Arrays.asList(ids));
    }

    /**
    * mq消息队列分页查询
    *
    * @param pageDto
    * @return List<AdmMq>
    */
    @Override
    public Page<AdmMqVo> list(AdmMqPageDto pageDto) throws InterruptedException {
        Page<AdmMq> tablesPage = new Page<>(pageDto.getPage(), pageDto.getLimit());
        QueryWrapper<AdmMq> queryWrapper = Wrappers.query();
        if (StringUtils.isNotEmpty(pageDto.getContent())){
            queryWrapper.like("name",pageDto.getContent());
        }
        queryWrapper.lambda().orderByAsc(AdmMq::getName);
        Page<AdmMq> pageSelectResult = admMqMapper.selectPage(tablesPage, queryWrapper);
        List<AdmMq> records = pageSelectResult.getRecords();
        List<AdmMqVo> voList = convertToVo(records);
        Page<AdmMqVo> page = new Page<>();
        page.setRecords(voList);
        page.setTotal(pageSelectResult.getTotal());
        page.setSize(pageSelectResult.getSize()); 
        return page;
    }

    @Override
    public List<AdmMqVo> convertToVo(List<AdmMq> records) throws InterruptedException {
        if (CollectionUtil.isEmpty(records)){
            return new ArrayList<>();
        }
        List<AdmMqVo> admMqVos = BeanUtils.copyList(records, AdmMqVo.class);
        List<Long> serverIds = admMqVos.stream().map(AdmMqVo::getServerId).collect(Collectors.toList());
        List<Server> serverList = serverService.getAll().stream().filter(s->serverIds.contains(s.getId())).collect(Collectors.toList());
        List<AdmDocker> dockerList = SpringUtils.getBean(AdmDockerServiceImpl.class).getAll()
                .stream().filter(s->serverIds.contains(s.getServerId())).collect(Collectors.toList());
        Map<String, List<Container>> containerMap = SpringUtils.getBean(AdmDockerServiceImpl.class).getContainerMap(dockerList);
        admMqVos.forEach(vo -> {
            Server serverVo = serverList.stream().filter(s -> s.getId().equals(vo.getServerId())).findFirst().orElse(null);
            vo.setIp(serverVo.getIp());
            AdmDocker admDocker = dockerList.stream().filter(s -> s.getServerId().equals(vo.getServerId())).findFirst().orElse(null);
            if (admDocker == null){
                vo.setStateName("未绑定docker");
            }else {
                List<Container> containers = containerMap.get("AdmDockerVo" + admDocker.getId());
                Container container = containers.stream().filter(s -> s.getId().equals(vo.getContainerId())).findFirst().orElse(null);
                if (container == null) {
                    vo.setStateName("未创建或超时");
                } else {
                    vo.setStateName(container.getState());
                }
            }
        });
        return admMqVos;
    }


    @Override
    public void installRabbitmq(String ids, String tempPath, MultipartFile rabbitmqFile) {
        long fileSize = rabbitmqFile.getSize();
        String[] split = ids.split(",");
        CountDownLatch mainLatch = new CountDownLatch(split.length);
        for (String id : split) {
            threadPoolTaskExecutor.execute(() -> {
                //上传包
                try {
                    AdmMq admMq = admMqMapper.selectById(id);
                    if (admMq.getDockerId() == null) {
                        return;
                    }
                    AdmDocker admDocker = admDockerMapper.selectById(admMq.getDockerId());
                    Server serverDocker = serverService.getServerById(admMq.getServerId());
                    Session session = remoteSshUtil.connect(serverDocker);
                    System.out.println("开始上传rabbitmq镜像文件");
                    //关闭防火墙
                    remoteSshUtil.exec(AutoConstants.DISABLE_FIREWALLD, session);
                    remoteSshUtil.exec(AutoConstants.STOP_FIREWALLD, session);
                    remoteSshUtil.exec(AutoConstants.AUTHORIZATION_FOLDER + tempPath, session);
                    CountDownLatch mainLatch2 = new CountDownLatch(1);
                    threadPoolTaskExecutor.execute(() -> {
                        try {
                            remoteSshUtil.putFile(session, rabbitmqFile, tempPath, fileSize, Long.parseLong(id), "mqInstall",serverDocker.getIp());
                        } catch (Exception e) {
                            throw new ServiceException(e.getMessage());
                        } finally {
                            mainLatch2.countDown();
                        }
                    });
                    mainLatch2.await();
                    sendMsg("installing", rabbitmqFile.getOriginalFilename(), Long.parseLong(id));
                    DockerClient dockerClient = dockerUtil.getDockerClientByDocker(SpringUtils.getBean(AdmDockerServiceImpl.class).convertToVo(admDocker));
                    dockerUtil.delContainer(dockerClient, "rabbitmq");
                    sendMsg("loading", rabbitmqFile.getOriginalFilename(), Long.parseLong(id));
                    //加载到镜像
                    remoteSshUtil.exec(StringUtils.format("docker load -i {}/{}", tempPath, rabbitmqFile.getOriginalFilename()), session);
                    //安装mysql
                    String info = StringUtils.format("docker run --restart=always --privileged=true -d --hostname my-rabbit --name rabbitmq \\\n" +
                            "-v /etc/localtime:/etc/localtime \\\n" +
                            "--network=host rabbitmq:latest");
                    System.out.println(info);
                    String exec = remoteSshUtil.exec(info, session);
                    System.out.println(exec);
                    admMq.setContainerId(exec.replace("\n", ""));
                    admMq.setInstallTime(new Date());
                    this.updateById(admMq);
                    sendMsg("starting", rabbitmqFile.getOriginalFilename(), Long.parseLong(id));
                    Thread.sleep(10 * 1000);
                    sendMsg("complete", rabbitmqFile.getOriginalFilename(), Long.parseLong(id));
                    remoteSshUtil.close(session);
                    dockerUtil.close(dockerClient);
                } catch (Exception e) {
                    e.printStackTrace();
                    alertFailMsg(e.getMessage());
                } finally {
                    mainLatch.countDown();
                }
            });
        }
        try {
            mainLatch.await();
            System.out.println("rabbitmq全部安装完毕");
            alertSuccessMsg("completeAll");
        } catch (InterruptedException e) {
            log.error(e.getMessage());
        }
    }
    private void sendMsg(String status, String name, Long id) {
        websocketEndPoint.send(WsSendDto.builder().type(0).table("mqInstall").status(status).name(name).id(id).build());
    }

    /**
     * 弹窗提示
     *
     * @param data
     */
    private void alertSuccessMsg(String data) {
        websocketEndPoint.send(WsSendDto.builder().type(2).table("mqInstall").data(data).build());
    }

    /**
     * 弹窗提示
     *
     * @param data
     */
    private void alertFailMsg(String data) {
        websocketEndPoint.send(WsSendDto.builder().type(3).table("mqInstall").data(data).build());
    }

}
